package elsim.controller


import org.apache.log4j.Logger
import org.joda.time.DateTime

import com.google.common.annotations.VisibleForTesting

import elsim.common.Clock
import elsim.entities.Lift
import elsim.entities.LiftManager;
import elsim.events.CallEvent
import elsim.events.DisplayEvent
import elsim.events.Event
import elsim.events.EventQueue
import elsim.events.FailEvent
import elsim.events.FixEvent
import elsim.events.StatsEvent

class EventController implements Controller {
  private static final Logger LOG = Logger.getLogger(EventController.class)

  int floors
  DateTime startTime

  @VisibleForTesting boolean liftInRange(int liftId) {
    if (liftId < lifts.length) {
      return true
    } else {
      LOG.warn("There's no lift with ID " + liftId)
      return false
    }
  }

  /**
   * Checks if new event happens after the top-most event in the queue
   * @param clock value
   * @return true iff clock is greater than latest event in queue
   */
  @VisibleForTesting boolean validEventTime(Event event) {
    if (EventQueue.getEventQueue().isEmpty()) {
      return true;
    } else {
      if (EventQueue.getEventQueue().peek().eventTime <= event.eventTime) {
        return true;
      } else {
        LOG.warn("This event appears to be out of sync and will be dropped: " + event.toString())
        return false
      }
    }
  }

  @VisibleForTesting void queueEvent(Event event) {
    if (validEventTime(event)) {
      EventQueue.getEventQueue().queueEvent(event)
    }
  }

  @Override
  public void onGlobalInit(int lifts, int floors, DateTime startTime) {
    LiftManager.getLiftManager().initialize(lifts);

    this.floors = floors
    this.startTime = startTime

    Clock.clock.resetClock(0)
  }

  @Override
  public void onInitLift(int lift, int position) {
    LiftManager.getLiftManager().getLift(lift).position = position
  }

  @Override
  public void onCall(String name, int from, int to, int clock) {
    CallEvent event = new CallEvent(name, from, to, clock);
    queueEvent(event)
  }

  @Override
  public void onFail(int lift, int clock) {
    FailEvent event = new FailEvent(lift, clock);
    queueEvent(event)
  }

  @Override
  public void onFix(int lift, int clock) {
    FixEvent event = new FixEvent(lift, clock);
    queueEvent(event)
  }

  @Override
  public void onDisplay(int clock) {
    DisplayEvent event = new DisplayEvent(clock)
    queueEvent(event)
  }

  @Override
  public void onStats(int clock) {
    StatsEvent event = new StatsEvent(clock)
    queueEvent(event)
  }
}
